package com.jacky.jpeg;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.support.v8.renderscript.Allocation;
import android.support.v8.renderscript.RenderScript;

import com.jacky.log.Logger;

import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import jacky.utils.rs.ScriptC_rotator;

public class RenderScriptRotation {

    public static Bitmap rotate90(Context mContext, Bitmap bitmap) {
        int targetHeight = bitmap.getWidth();
        int targetWidth = bitmap.getHeight();
        Bitmap.Config config = bitmap.getConfig();

        RenderScript rs = RenderScript.create(mContext);
        ScriptC_rotator script = new ScriptC_rotator(rs);
        script.set_inWidth(targetHeight);
        script.set_inHeight(targetWidth);
        Allocation sourceAllocation = Allocation.createFromBitmap(rs, bitmap,
                Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
        bitmap.recycle();
        script.set_inImage(sourceAllocation);

        Bitmap target = Bitmap.createBitmap(targetWidth, targetHeight, config);
        final Allocation targetAllocation = Allocation.createFromBitmap(rs, target,
                Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
        script.forEach_rotate_90_clockwise(targetAllocation, targetAllocation);
        targetAllocation.copyTo(target);
        rs.destroy();
        return target;
    }

    public static Bitmap rotate270(Context mContext, Bitmap bitmap) {
        int targetHeight = bitmap.getWidth();
        int targetWidth = bitmap.getHeight();
        Bitmap.Config config = bitmap.getConfig();

        RenderScript rs = RenderScript.create(mContext);
        ScriptC_rotator script = new ScriptC_rotator(rs);
        script.set_inWidth(targetHeight);
        script.set_inHeight(targetWidth);
        Allocation sourceAllocation = Allocation.createFromBitmap(rs, bitmap,
                Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
        bitmap.recycle();
        script.set_inImage(sourceAllocation);

        Bitmap target = Bitmap.createBitmap(targetWidth, targetHeight, config);
        final Allocation targetAllocation = Allocation.createFromBitmap(rs, target,
                Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
        script.forEach_rotate_270_clockwise(targetAllocation, targetAllocation);
        targetAllocation.copyTo(target);
        rs.destroy();
        return target;
    }

    public static Bitmap rotate180(Context mContext, Bitmap bitmap) {
        int targetHeight = bitmap.getWidth();
        int targetWidth = bitmap.getHeight();
        Bitmap.Config config = bitmap.getConfig();

        RenderScript rs = RenderScript.create(mContext);
        ScriptC_rotator script = new ScriptC_rotator(rs);
        script.set_inWidth(targetHeight);
        script.set_inHeight(targetWidth);
        Allocation sourceAllocation = Allocation.createFromBitmap(rs, bitmap,
                Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
        bitmap.recycle();
        script.set_inImage(sourceAllocation);

        Bitmap target = Bitmap.createBitmap(targetHeight, targetWidth, config);
        final Allocation targetAllocation = Allocation.createFromBitmap(rs, target,
                Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
        script.forEach_rotate_180_clockwise(targetAllocation, targetAllocation);
        targetAllocation.copyTo(target);
        rs.destroy();
        return target;
    }

    public static void saveImage(Context context, int rotate, byte[] bitmapDatas, File file, boolean removeIccProf) {
        if(rotate == 0) {
            //不需要旋转的图片，直接写入磁盘
            writeData(bitmapDatas, file);
            return;
        }

        Bitmap bm  = BitmapFactory.decodeByteArray(bitmapDatas, 0, bitmapDatas.length);
        bitmapDatas = null;

        if(rotate == 90) {
            bm = RenderScriptRotation.rotate90(context, bm);
        } else if(rotate == 180) {
            bm = RenderScriptRotation.rotate180(context, bm);
        } else if(rotate == 270){
            bm = RenderScriptRotation.rotate270(context, bm);
        } else {
            throw new IllegalArgumentException("rotate err,only 90/180/270.but input " + rotate);
        }

        if(removeIccProf) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            bm.compress(Bitmap.CompressFormat.JPEG,90,baos);
            bm.recycle();
            bitmapDatas = baos.toByteArray();
            bitmapDatas = skipBitmapIccProf(bitmapDatas);
            writeData(bitmapDatas, file);
        } else {
            FileOutputStream stream2 = null;
            try {
                stream2 = new FileOutputStream(file);
                bm.compress(Bitmap.CompressFormat.JPEG, 90, stream2);
                bm.recycle();
            } catch (Exception e) {
                Logger.e(e);
            } finally {
                close(stream2);
            }
        }
    }

    private static void close(Closeable closeable) {
        if(closeable == null) return;
        try {
            closeable.close();
        } catch (IOException e) {
        }
    }

    private static void writeData(byte[] datas, File file) {
        FileOutputStream stream2 = null;
        try {
            stream2 = new FileOutputStream(file);
            stream2.write(datas);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(stream2);
        }
    }

    private static byte[] skipBitmapIccProf(byte[] datas) {
        int startPos = -1, iccLength = 0;
        for(int i = 2; i < 300;i++) {//2和200没什么意义，只是减少次数而已
            //0x02  0x40  0x49  0x43  0x43
            if(datas[i] !=  0x02) continue;
            if(datas[i + 1] !=  0x40) continue;
            if(datas[i + 2] !=  0x49) continue;
            if(datas[i + 3] !=  0x43) continue;
            if(datas[i + 4] !=  0x43) continue;

            //找到了ICC标识的位置
            startPos = i - 2;
            iccLength = datas[i - 1] & 0xff;//ICC_PROF属性的数据范围长度
            break;
        }

        if(startPos == -1)  return datas;
        byte[] dd = new byte[datas.length - iccLength];
        System.arraycopy(datas, 0, dd, 0, startPos);
        System.arraycopy(datas, startPos + iccLength, dd, startPos, dd.length - startPos);
        return dd;
    }
}
